import wx
import math 
from scipy.ndimage import gaussian_filter1d
import numpy
from log_object import *

def makeNew(parent, window, param1):
    """ this is how we instantiate the device object from
        the main program that loads this plugin """
    return VectorGraph(parent, window, param1)

class VectorGraph:
	def __init__(self, parent, window, param1):
		self.parent = parent
		self.window = window

		self.type = VECTORGRAPH
		self.param1 = param1
		self.param2 = NOT_DEFINED 

		self.log_date = ""
		self.start = 0
		self.end = 0 
		self.panel_end = 0 
		self.dim = [] 
		self.space = [] 

	def draw(self, dc, start, end, dim, space):
		self.draw_all(dc, start, end, dim, space)
		#self.draw_each(dc, start, end, dim, space)

	def draw_each(self, dc, start, end, dim, space):
		foreground = self.parent.getForegroundColor()
		background = self.parent.getBackgroundColor()

		self.start = start
		self.end = end 
		self.panel_end =  end 
		self.dim = dim
		self.space = space

		dc.SetBrush(wx.TRANSPARENT_BRUSH)
		dc.SetPen(wx.Pen(foreground, 1))
		dc.SetTextBackground(background)
		dc.SetTextForeground(foreground)
		font = wx.Font(15, wx.TELETYPE, wx.NORMAL, wx.BOLD)
		dc.SetFont(font)

		window_width = int(self.window.Width / space[0])
		window_height = int(self.window.Height / space[1])

		no_user = len(self.parent.selected_user_list)
		no_log =  len(self.parent.log_list)
		if no_user == 1 and no_log > 1 :
			no_user = no_log

		row_height = self.window.Height
		if no_user > 0 : 
			row_height = int((self.window.Height - 61) / no_user)  

		display_width = DISPLAY_WIDTH
		display_height = DISPLAY_HEIGHT
		for current_log in self.parent.log_list :
			display_width = current_log.display_width
			display_height = current_log.display_height
			break	

		ratio =  (display_width * 1.0) / display_height
		spare = int(window_width * 0.15)
		portion = 0.7
		if self.dim[0] == 1 or self.space[0] >= 2: 
			spare = 10 
			portion = 0.5

		graph_width = (window_width -spare) -50
		graph_height = int(graph_width / ratio)
		#print "graph configuration=>", graph_width, graph_height

		temp_height = window_height - 20
		label_height = window_height
		if no_user > 0 :
			temp_height = int((window_height - (no_user +1) *10) / no_user)
			label_height = window_height / no_user
		if graph_height > temp_height: 
			graph_height = temp_height 
			graph_width =  int(graph_height * ratio)
		row_height =  row_height - graph_height  
		if self.space[0] == 1 :
			row_height = 0

		x = (self.dim[0] * window_width) + int((window_width -graph_width) * portion)
		y = (self.dim[1] * window_height) + 10  + int(row_height / 2.0)

		log_idx = 0 
		for current_log in self.parent.log_list :
			log_end = current_log.duration
			self.log_date = current_log.date
			if self.panel_end == - 1 :
				self.end = -1
			if self.end == -1 or self.end > current_log.duration:
				self.end = current_log.duration

			for pointer in current_log.pointer_list: 
				if self.parent.isSelectedUser(pointer.name) == False:
					continue

				# draw display area
				dc.SetBrush(wx.TRANSPARENT_BRUSH)
				dc.SetPen(wx.Pen(foreground, 1))
				dc.DrawRectangle(x, y, graph_width+66, graph_height)
				dc.DrawLines(((5, y+graph_height+10), (window_width, y+graph_height+10)))

				# draw title
				if self.space[0] == 1 : 
					len_name = len(pointer.name) * 10 + 70
					dc.DrawText(pointer.name, x - len_name , y + graph_height - 20)

				# draw window
				#dc.SetPen(wx.Pen(foreground, 1))
				#dc.DrawRectangle(x, y, graph_width, graph_height)
				#dc.DrawLines(((x-50, y+graph_height),  (x+graph_width+50, y+graph_height)))

				dc.SetPen(wx.Pen(wx.Colour(0,0,255), 1))
				prev_x = -1
				prev_y = -1
				dir_x = 0
				dir_y = 0
				count = 0

				count = 0
				line_list = []
				line = []
				prev_time = -1
				# draw vector 
				for log in pointer.log_list: 
					if log.mode == LOG_POINTER_MOVE :
						log_min = log.time / 60
						if log_min < self.start or log_min > self.end :
							continue

						x1 = int(log.x * graph_width / display_width) + x
						y1 = int(log.y * graph_height / display_height)  + y

						if prev_time == -1 :
							prev_time = log.time
							line.append((x1, y1))
						else :
							diff_time = log.time - prev_time
							if diff_time <= 1.0 :
								prev_time = log.time
								line.append((x1, y1))
							else :
								if len(line) > 0 : 
									line_list.append(line)
									line = []
									line.append((x1, y1))
								prev_time = -1
 					elif log.mode == LOG_POINTER_REMOVE :
						prev_time = -1
						if len(line) > 0 : 
							line_list.append(line)
							line = []
 					elif log.mode == LOG_POINTER_NEW :
						prev_time = -1
 					elif log.mode == LOG_POINTER_CLICK:
						prev_time = -1
						if len(line) > 0 : 
							line_list.append(line)
							line = []
				if len(line) > 0 : 
					line_list.append(line)
					line = []

				color_idx = 1 
				for line in line_list: 
					last_idx = len(line) -1
					if last_idx >= 1 : 
						color = self.parent.color_mgr.getColor(color_idx + 10) 
						dc.SetPen(wx.Pen(color, 1))

						last_pnt = line[last_idx]
						interPoints = self.interpolate(line, 16)
						curvedPoints = self.smoothListGaussian(interPoints, 4)
						curvedPoints.append(last_pnt)
						dc.DrawLines(curvedPoints)
						del interPoints
						del curvedPoints
						dc.DrawCircle(last_pnt[0],last_pnt[1],5)

						first_pnt = line[0]
						dx = last_pnt[0] - first_pnt[0] 
						dy = last_pnt[1] - first_pnt[1] 
						unit_length = math.sqrt(dx * dx +  dy * dy)
						if unit_length > 0 : 
       							unitDx = dx / unit_length * 15;
							unitDy = dy / unit_length * 15;
							if math.fabs(unitDx) > math.fabs(unitDy) :  
								dir_x += 1
							else :
								dir_y += 1
						count += 1
						if color_idx == 8 : 
							color_idx =1
						else :
							color_idx += 1 
					else  :
						print line


				dir_x = int((dir_x * 1.0 / count) * 100)
				dir_y = int((dir_y * 1.0 / count) * 100)
				dc.DrawText("x dir.: " + str(dir_x) + "%", 30 , y + graph_height - 70)
				dc.DrawText("y dir.: " + str(dir_y) + "%", 30 , y + graph_height - 50)

				y += graph_height + row_height +  10

				del line_list

				font = wx.Font(12, wx.TELETYPE, wx.NORMAL, wx.BOLD)
				dc.SetFont(font)
				x_label = 30
				y_label = (self.dim[1] * window_height) + 10 + (log_idx * label_height)
				dc.DrawText(self.log_date, x_label, y_label)

				dc.DrawText("mouse", x_label, y_label+20)
				dc.DrawText("vector", x_label, y_label + 35)

				dc.DrawText("start: " + str(self.start), x_label, y_label + 60)
				dc.DrawText("end: " + str(self.end), x_label, y_label + 75)
				dc.DrawText("     /" + str(self.panel_end), x_label, y_label + 90)
			log_idx += 1

	def draw_all(self, dc, start, end, dim, space):
		foreground = self.parent.getForegroundColor()
		background = self.parent.getBackgroundColor()

		self.start = start
		self.end = end 
		self.panel_end =  end 
		self.dim = dim
		self.space = space

		dc.SetBrush(wx.TRANSPARENT_BRUSH)
		dc.SetPen(wx.Pen(foreground, 1))
		dc.SetTextBackground(background)
		dc.SetTextForeground(foreground)
		font = wx.Font(15, wx.TELETYPE, wx.NORMAL, wx.BOLD)
		dc.SetFont(font)

		window_width = int(self.window.Width / space[0])
		window_height = int(self.window.Height / space[1])

		no_user = len(self.parent.selected_user_list)
		no_log =  len(self.parent.log_list)
		if no_user == 1 and no_log > 1 :
			no_user = no_log

		row_height = self.window.Height
		if no_user > 0 : 
			row_height = int((self.window.Height - 61) / no_user)  

		display_width = DISPLAY_WIDTH
		display_height = DISPLAY_HEIGHT
		for current_log in self.parent.log_list :
			display_width = current_log.display_width
			display_height = current_log.display_height
			break	
		for current_log in self.parent.log_list :
			for pointer in current_log.pointer_list: 
				for log in pointer.log_list: 
					if log.mode == LOG_POINTER_MOVE :
						log.x
						if log.x > display_width : 
							display_width = log.x
						if log.y > display_height : 
							display_height = log.y

		ratio =  (display_width * 1.0) / display_height
		spare = int(window_width * 0.15)
		portion = 0.7
		if self.dim[0] == 1 or self.space[0] >= 2: 
			spare = 10 
			portion = 0.5

		graph_width = (window_width -spare) -50
		graph_height = int(graph_width / ratio)
		#print "graph configuration=>", graph_width, graph_height

		temp_height = window_height - 20
		label_height = window_height
		if no_user > 0 :
			temp_height = int((window_height - (no_user +1) *10) / no_user)
			label_height = window_height / no_user
		if graph_height > temp_height: 
			graph_height = temp_height 
			graph_width =  int(graph_height * ratio)
		row_height =  row_height - graph_height  
		if self.space[0] == 1 :
			row_height = 0

		#x = 100
		x = int((window_width -graph_width) * portion)
		y = 10  + int(row_height / 2.0)

		log_idx = 0 
		for current_log in self.parent.log_list :
			log_end = current_log.duration
			self.log_date = current_log.date
			if self.panel_end == - 1 :
				self.end = -1
			if self.end == -1 or self.end > current_log.duration:
				self.end = current_log.duration

			line_list = []
			dc.SetBrush(wx.TRANSPARENT_BRUSH)
			dc.SetPen(wx.Pen(foreground, 1))
			dc.DrawRectangle(x, y, graph_width, graph_height)
			dc.DrawLines(((5, y+graph_height+10), (window_width, y+graph_height+10)))

			for pointer in current_log.pointer_list: 
				dc.SetPen(wx.Pen(wx.Colour(0,0,255), 1))
				prev_x = -1
				prev_y = -1
				dir_x = 0
				dir_y = 0
				count = 0

				count = 0
				line = []
				prev_time = -1
				# draw vector 
				for log in pointer.log_list: 
					if log.mode == LOG_POINTER_MOVE :
						log_min = log.time / 60
						if log_min < self.start or log_min > self.end :
							continue

						x1 = int(log.x * graph_width / display_width) + x
						y1 = int(log.y * graph_height / display_height)  + y

						if prev_time == -1 :
							prev_time = log.time
							line.append((x1, y1))
						else :
							diff_time = log.time - prev_time
							if diff_time <= 1.0 :
								prev_time = log.time
								line.append((x1, y1))
							else :
								if len(line) > 0 : 
									line_list.append(line)
									line = []
									line.append((x1, y1))
								prev_time = -1
 					elif log.mode == LOG_POINTER_REMOVE :
						prev_time = -1
						if len(line) > 0 : 
							line_list.append(line)
							line = []
 					elif log.mode == LOG_POINTER_NEW :
						prev_time = -1
 					elif log.mode == LOG_POINTER_CLICK:
						prev_time = -1
						if len(line) > 0 : 
							line_list.append(line)
							line = []
				if len(line) > 0 : 
					line_list.append(line)
					line = []

			color_idx = 1 
			for line in line_list: 
				last_idx = len(line) -1
				if last_idx >= 1 : 
					color = self.parent.color_mgr.getColor(color_idx + 10) 
					dc.SetPen(wx.Pen(color, 1))

					last_pnt = line[last_idx]
					interPoints = self.interpolate(line, 16)
					curvedPoints = self.smoothListGaussian(interPoints, 4)
					curvedPoints.append(last_pnt)
					dc.DrawLines(curvedPoints)
					del interPoints
					del curvedPoints
					dc.DrawCircle(last_pnt[0],last_pnt[1],5)

					first_pnt = line[0]
					dx = last_pnt[0] - first_pnt[0] 
					dy = last_pnt[1] - first_pnt[1] 
					unit_length = math.sqrt(dx * dx +  dy * dy)
					if unit_length > 0 : 
       						unitDx = dx / unit_length * 15;
						unitDy = dy / unit_length * 15;
						if math.fabs(unitDx) > math.fabs(unitDy) :  
							dir_x += 1
						else :
							dir_y += 1
					count += 1
					if color_idx == 8 : 
						color_idx =1
					else :
						color_idx += 1 
				else  :
					print line


			dir_x = int((dir_x * 1.0 / count) * 100)
			dir_y = int((dir_y * 1.0 / count) * 100)
			dc.DrawText("x dir.: " + str(dir_x) + "%", 30 , y + graph_height - 70)
			dc.DrawText("y dir.: " + str(dir_y) + "%", 30 , y + graph_height - 50)

			y += graph_height + row_height +  10

			del line_list

			font = wx.Font(12, wx.TELETYPE, wx.NORMAL, wx.BOLD)
			dc.SetFont(font)
			x_label = 30
			y_label = (self.dim[1] * window_height) + 10 + (log_idx * label_height)
			dc.DrawText(self.log_date, x_label, y_label)

			dc.DrawText("mouse", x_label, y_label+20)
			dc.DrawText("vector", x_label, y_label + 35)

			dc.DrawText("start: " + str(self.start), x_label, y_label + 60)
			dc.DrawText("end: " + str(self.end), x_label, y_label + 75)
			dc.DrawText("     /" + str(self.panel_end), x_label, y_label + 90)
			log_idx += 1


	def interpolate(self, pts, sigma):
		res = []
		tension = 1.0 / sigma
		max = len(pts) - 1
		for i in range(max) :
			mag = 0.0
			for t in range(sigma) :
				dir = ((pts[i+1][0] - pts[i][0]) *mag, (pts[i+1][1] - pts[i][1])*mag)
				p = (pts[i][0] + dir[0], pts[i][1]+ dir[1])
				res.append(p)
				mag += tension
		return res


	def smoothListGaussian(self, pts, sigma):
		a=numpy.array(pts)
		x, y = a.T
		t = numpy.linspace(0, 1, len(x))
		t2 = numpy.linspace(0, 1, 100)

		x2 = numpy.interp(t2, t, x)
		y2 = numpy.interp(t2, t, y)
		x3 = gaussian_filter1d(x2, sigma)
		y3 = gaussian_filter1d(y2, sigma)

		x4 = numpy.interp(t, t2, x3)
		y4 = numpy.interp(t, t2, y3)

		res = []
		max = len(x4)
		for i in range(max) :
			p = (x4[i], y4[i])
			res.append(p)
		return res

